import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

import VueDevTools from "vite-plugin-vue-devtools";

import fs from "fs";
import path from "path";

// 读取 package.json 文件并解析为 JSON 对象
const packageJsonPath = path.resolve(__dirname, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));

// mode 参数值从 package.json scripts 中配置的脚本（如："build": "vite build --mode build"）中的参数传入
export default defineConfig(({ mode }) => {
  const isBuild = mode === "build";

  return {
    root: isBuild ? "." : "./example",
    plugins: [
      vue(),
      VueDevTools({
        launchEditor: "code",
        componentInspector: {
          enabled: true,
          toggleButtonVisibility: "always",
          launchEditor: "code",
        },
      }),
    ],
    build: {
      outDir: "dist",
      target: "es2020",
      /*
        build.lib 是专门用于构建库（library）的配置项。
          当你希望将项目打包成一个可以被其他项目引用的库时，使用这个选项。
      */
      lib: {
        // 若不指定，则项目构建默认的入口文件为「项目根目录/index.html」。
        // 指定项目构建的入口文件，即从哪个文件开始构建。
        // entry: "example/src/main.ts",
        entry: isBuild ? "src/index.ts" : "example/src/main.ts",
        // 构建后生成的文件格式
        // 若不指定 fileName，则文件名默认为 package.json 中的 name 字段，es -> [name].js, cjs -> [name].cjs
        formats: ["es", "cjs"],
        // 构建后生成的文件名
        // format 为 es 或 cjs，entryName 为入口文件名。
        // 若 build.lib.entry 配置项指定了入口文件为 src/index.ts ，则 entryName 为 index 。
        fileName: (format, entryName) => {
          const name = packageJson.name ? packageJson.name : entryName;
          return format === "es" ? `es/${name}.js` : `cjs/${name}.cjs`;
        },
      },
      /*
        是否启用「映射源」：
          开发环境：
            启用「映射源」可以帮助开发者在浏览器中调试 Vue 源代码。
          生产环境：
            由于源代码已经被编译为 JavaScript，因此不需要「映射源」，以减少文件大小和加载时间。
            因此，在生产环境中，通常将 sourcemap 设置为 false，以提高性能和安全性。
        启用「映射源」后，
          1.执行 npm run dev 后，通常执行的是 `vite` 脚本，进入 Vite 开发模式。
            Vite 开发模式下：★★★★★★★
              虽然，无法显式看到「源映射文件（即 sourcemap 文件）」，
              但，浏览器会同时加载源代码和 Vue 编译后的代码，
              以便在开发过程中进行调试（打开浏览器控制台 -> Sources）。
          2.构建项目时，将生成 sourcemap 文件，格式为 [file-name].js.map（更多详见下方 outDir 配置项）。
      */
      sourcemap: true, // 启用源映射
      rollupOptions: {
        /*
          若无此配置，则
          问题描述：
            执行 npm run build 后，「package.json -> exports -> . -> default 」值，
            由 ./src/index.ts 改为 ./dist/es/nav-tab.js ， 
            引用了 nav-tab 的项目（通过 "nav-tab": "file:../nav-tab", 进行本地引用，便于调试），
            运行后，浏览器访问报错：
              nav-tab.js?v=c528d7e9:1403 Uncaught TypeError: Cannot read properties of null (reading 'ce')
                at Ke (nav-tab.js?v=c528d7e9:1403:9)
                at Proxy.<anonymous> (nav-tab.js?v=c528d7e9:2086:9)
                at renderComponentRoot (vue.js?v=fa874b9f:8706:17)
                at ReactiveEffect.componentUpdateFn [as fn] (vue.js?v=fa874b9f:7511:46)
                at ReactiveEffect.run (vue.js?v=fa874b9f:505:19)
                at setupRenderEffect (vue.js?v=fa874b9f:7646:5)
                at mountComponent (vue.js?v=fa874b9f:7420:7)
                at processComponent (vue.js?v=fa874b9f:7372:9)
                at patch (vue.js?v=fa874b9f:6886:11)
                at mountChildren (vue.js?v=fa874b9f:7120:7)
          分析：
            错误 TypeError: Cannot read properties of null (reading 'ce') 表明在运行时，
            组件试图访问一个 null 对象的属性。这种情况通常发生在：
              1.构建过程没有正确编译 Vue 组件。
              2.开发环境和生产环境构建之间存在不匹配。
              3.组件没有被正确导出或导入。
          关键观察点：
            你的 package.json 中配置了 exports 字段，开发环境指向 ./src/index.ts，生产环境指向 ./dist/es/nav-tab.js 。
            错误发生在运行 npm run build 生成生产构建之后。
            错误源自构建后的 nav-tab.js 文件。
          解决方案：
            在确保 package.json exports 字段配置正确之后，在此处添加 `external: ['vue'],` 配置项。
            从而避免在构建项目时， Vue 被打包进库中。
        */
        // 确保 Vue 不会被打包进你的库中 ★★★★★★★
        external: ['vue'],
        output: {
          /*
            可选，因为 ES 模块和 CommonJS 不依赖于全局变量。
            如果你计划构建 UMD 格式，那么 globals 是推荐配置的。
            即使当前只使用 ES 和 CJS 格式（详见上面 lib.formats 配置），保留 globals 配置也是好的实践，因为：
              1.未来可能添加 UMD 格式支持
              2.它使配置更完整和清晰
              3.不会产生负面影响
          */
          // 为外部依赖提供全局变量名，如 `vue: 'Vue'` 中，`vue` 为外部依赖的名称，`Vue` 为全局变量名。
          globals: {
            vue: 'Vue'
          }
        }
      },
      /*
         cssCodeSplit: false 的含义和默认值
          cssCodeSplit 是 Vite 构建配置中的一个选项，
            它控制在构建过程中是否将 CSS 代码拆分成多个独立的文件。

          当设置为 false 时：
            所有的 CSS 样式将会被打包到一个单独的文件中（在这个项目中是 dist/nav-tab.css）。
            这对于构建库项目特别有用，因为用户可以只引入一个 CSS 文件就能获得所有组件的样式。
          默认值：
            在 Vite 中，cssCodeSplit 的默认值取决于构建模式。
            对于普通项目构建（非库模式），默认值为 true，即会根据代码分割策略将 CSS 拆分成多个文件。
            对于库模式构建（即配置了 build.lib），默认值为 false，与你在配置中显式设置的值一致。
          由于当前项目是一个 Vue 组件库，
            因此设置 cssCodeSplit: false 是合理的，
            确保所有组件的样式都集中在一个 CSS 文件中，方便用户引入和使用。
      */
      cssCodeSplit: false
    },
    /*
      支持对 CSS 进行更精细的控制，比如：
        1. 添加全局样式变量、预处理器配置，如可以为 Sass、Less、Stylus 等预处理器提供全局选项。
        2. CSS Modules 配置。
        3. PostCSS 配置。
        4. URL 处理配置。
        等等。
    */
    css: {}
  };
});
